package labrom.usage;

import java.io.UnsupportedEncodingException;
import java.nio.ByteBuffer;
import java.util.Collection;
import java.util.LinkedList;

import org.apache.http.HttpEntity;
import org.apache.http.entity.ByteArrayEntity;

public class Batch extends LinkedList<Udi> {
	
	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	
	private long created = System.currentTimeMillis();
	private int sentStartingAtIndex;
	private long sentStartingAtTimestamp;
	
	private int capacity;
	
	public Batch(int capacity) {
		this.capacity = capacity;
	}
	

	/**
	 * 
	 * @param timestamp items shouldn't be older than this timestamp (unless value is 0, which means don't filter out items)
	 * @return an HTTP entity, or null if the batch is empty
	 * @throws UnsupportedEncodingException
	 */
	public HttpEntity createHttpEntity(long timestamp) throws UnsupportedEncodingException {
		if(isEmpty())
			return null;
		
		ByteBuffer buffer = null;
		if(timestamp == 0) {
			buffer = ByteBuffer.allocate(size() * 8 * 2);
			for(Udi u : this) {
				buffer.putLong(u.getTimestamp());
				buffer.putLong(u.getTypeId());
			}
		} else {
			int index = 0;
			for(Udi u : this) {
				long ts = u.getTimestamp();
				if(buffer == null && ts >= timestamp) {
					buffer = ByteBuffer.allocate((size() - index) * 8 * 2);
					sentStartingAtIndex = index;
					sentStartingAtTimestamp = ts;
				}
					
				if(buffer != null) {
					buffer.putLong(ts);
					buffer.putLong(u.getTypeId());
				}
				index ++;
			}
		}
		return buffer != null ? new ByteArrayEntity(buffer.array()) : null;
	}
	
	public Batch peek(int maxSize) {
		Batch b = new Batch(maxSize);
		if(size() <= maxSize)
			b.addAll(this);
		else
			b.addAll(this.subList(0, maxSize));
		return b;
	}
	
	
	/**
	 * Removes all items whose timestamp if lower than or equal to the provided timestamp.
	 * @param timestamp
	 * @return the number of items that were removed
	 */
	public int stripBeforeTimestamp(long timestamp) {
		int index = 0;
		for(Udi u : this) {
			if(u.getTimestamp() > timestamp)
				break;
			index ++;
		}
		if(index > 0 && index <= size())
			this.removeRange(0, index);
		return index;
	}


	public int getSentStartingAtIndex() {
		return sentStartingAtIndex;
	}


	public long getSentStartingAtTimestamp() {
		return sentStartingAtTimestamp;
	}


	public long getCreated() {
		return created;
	}
	
	/**
	 * Implement sliding queue functionality.
	 */
	@Override
	public boolean add(Udi object) {
		if(size() >= capacity)
			removeFirst();
		return super.add(object);
	}
	
	/**
	 * Implement sliding queue functionality.
	 */
	@Override
	public boolean addAll(Collection<? extends Udi> collection) {
		int size = size() + collection.size();
		if(size > capacity)
			removeRange(0, size - capacity);
		return super.addAll(collection);
	}
	
	/**
	 * Implement sliding queue functionality.
	 */
	@Override
	public void addLast(Udi object) {
		if(size() >= capacity)
			removeFirst();
		super.addLast(object);
	}

}
